#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "pthread.h"

#include "BList.h"
#include "BVector.h"
#include "geometrics.h"
#include "quaternion.h"
#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "AWEntity.h"
#include "AWMessage.h"
#include "AWBrain.h"
#include "AWTracerBrain.h"
#include "AWThreadedBrain.h"
#include "AWNOOSBrain.h"
#include "AWNOOSLearnerBrain.h"

#include "CaseBaseUtils.h"

#include "psm.h"

#include "loader.h"



FeatureTerm *AW_NOOSLearnerBrain::solve_problem_JEC(FeatureTerm *problem,Sort *sort,Symbol *my_name)
{
	int i;
	char *str;
	AW_Message *m;
	Symbol *agent_name;
	List<Symbol> agent_names;
	FeatureTerm *prediction,*JER,*XER,*f,*op,*solution_record;
	List<FeatureTerm> individual_solutions;
	List<FeatureTerm> JERs;
	List< List< FeatureTerm> > XERs;
	List<float> JER_Cs;

	/* Retrieve the set of other agents: */ 
	pthread_mutex_lock(&m_sensor_data_mutex);
	m_sensor_data.Rewind();
	while(m_sensor_data.Iterate(f)) {						
		if (f->getSort()->is_a(m_ontology->get_sort("sensed-agent")) &&
			!f->getSort()->is_a(m_ontology->get_sort("sensed-self"))) {
			Symbol *name=f->featureValueQuick("name")->getSymbol();
			if (name->get()[0]=='L' &&
				name->get()[1]=='e' &&
				name->get()[2]=='a' &&
				name->get()[3]=='r' &&
				name->get()[4]=='n' &&
				name->get()[5]=='e' &&
				name->get()[6]=='r') {
				agent_names.Add(new Symbol(name));
			} /* if */ 
		} /* if */ 	
	} /* while */ 
	pthread_mutex_unlock(&m_sensor_data_mutex);

	/* Do not use all the agents: */ 
/*
	{
		delete agent_names.ExtractIni();
		delete agent_names.ExtractIni();
		delete agent_names.ExtractIni();
//		delete agent_names.ExtractIni();
	}
*/

	/* Send the problem to the other agents: */ 
	agent_names.Rewind();
	while(agent_names.Iterate(agent_name)) {
		/* Send the problem: */ 
		f=new FeatureTerm((char *)0,m_ontology->get_sort("request-individual-predict-message"),1,
						  "problem",new FeatureTerm(problem));

		str=f->toStringNOOS(m_memory);
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
						   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
		delete []str;
		delete f;
		enqueue_operator(op);
	} /* while */ 

	/* Solve the problem individually: */ 
	individual_solutions.Add(build_jers(problem,sort,my_name));

	/* Receive the solution from the others: */ 
	for(i=0;i<agent_names.Length();i++) {
		/* Wait for the confirmation of the agent: */ 
		wait_message();
		m=get_message();
		prediction=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
		individual_solutions.Add(prediction);
		delete m;
	} /* for */ 

	/* Construct the list of JERs: */ 
	write_debug_report("[Learner]: With %i agents.\n",individual_solutions.Length());
	individual_solutions.Rewind();
	while(individual_solutions.Iterate(prediction)) {
		if (prediction->isFeatureTerm()) {
			JERs.Add(new FeatureTerm(prediction));
			XERs.Add(new List<FeatureTerm>);
		} else {
			List<FeatureTerm> *l;
			l=prediction->set_values_quick();
			l->Rewind();
			while(l->Iterate(prediction)) {
				JERs.Add(new FeatureTerm(prediction));
				XERs.Add(new List<FeatureTerm>);
			} /* while */ 
		} /* if */ 
	} /* while */ 
	write_debug_report("[Learner]: %i JERs collected.\n",JERs.Length());

	/* Request XERs from all the other agents for all the JERs: */ 
	{
		FeatureTerm *JER_set=FeatureTerm::SetFeatureTerm((Symbol *)0);
		Symbol *s_tmp;

		JERs.Rewind();
		while(JERs.Iterate(JER)) {
			JER_set->addSetValue(new FeatureTerm(JER));
		} /* while */ 
		f=new FeatureTerm((char *)0,m_ontology->get_sort("request-examination-message"),2,
						  "problem",new FeatureTerm(problem),
						  "prediction",new FeatureTerm(JER_set));
		str=f->toStringNOOS(m_memory);
		s_tmp=new Symbol(str);

		agent_names.Rewind();
		while(agent_names.Iterate(agent_name)) {
			/* Send the problem: */ 

			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s_tmp),m_ontology));
			enqueue_operator(op);
		} /* while */ 

		delete s_tmp;
		delete []str;
		delete f;
		delete JER_set;
	}

	/* Locally examine the JERs: */ 
	JERs.Rewind();
	while(JERs.Iterate(JER)) {
		XER=examine_JER(JER,sort);
		i=JERs.Position(JER);
		if (i!=-1) {
			XERs[i]->Add(XER);
		} /* if */ 
	} /* while */ 

	/* Receive the examination from all the other agents: */ 
	for(i=0;i<agent_names.Length();i++) {
		int j;
		/* Wait for the examinations of the agent: */ 
		wait_message();
		m=get_message();
		
		f=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
		if (f->isFeatureTerm()) {
			XERs[0]->Add(new FeatureTerm(f));
		} else {
			List<FeatureTerm> *l;
			l=f->set_values_quick();
			j=0;
			l->Rewind();
			while(l->Iterate(XER)) {
				XERs[j]->Add(new FeatureTerm(XER));
				j++;
			} /* while */ 
		} /* if */ 	
		delete f;
		delete m;
	} /* for */ 

	for(i=0;i<JERs.Length();i++) {
		int j;
		write_debug_report("For JER%i (%s): ",i,JERs[i]->featureValueQuick("solution")->getName()->get());
		for(j=0;j<XERs[i]->Length();j++) {
			write_debug_report("(%i,%i) ",XERs[i]->operator [](j)->featureValueQuick("endorsing-cases")->getInt(),
										  XERs[i]->operator [](j)->featureValueQuick("counter-examples")->getInt());
		} /* for */ 
		write_debug_report("\n");
	} /* for */ 

	/* Compute the confidence values of the JERs: */ 
	for(i=0;i<JERs.Length();i++) {
		int Y=0,N=0;
		int j;
		for(j=0;j<XERs[i]->Length();j++) {
			Y+=XERs[i]->operator [](j)->featureValueQuick("endorsing-cases")->getInt();
			N+=XERs[i]->operator [](j)->featureValueQuick("counter-examples")->getInt();
		} /* for */ 
		JER_Cs.Add(new float(float(Y)/float(1+Y+N)));
	} /* for */ 

	for(i=0;i<JER_Cs.Length();i++) {
		write_debug_report("C(%i) = %g\n",i,*JER_Cs[i]);
	} /* for */ 

	/* Aggregate the solutions: */ 
	{
		int pos;
		List<FeatureTerm> solutions;
		List<float> votes;
		FeatureTerm *solution;
		int selected;

		for(i=0;i<JERs.Length();i++) {
			solution=JERs[i]->featureValueQuick("solution");
			pos=solutions.Position(solution);
			if (pos==-1) {
				solutions.Add(new FeatureTerm(solution));
				votes.Add(new float(*JER_Cs[i]));
			} else {
				*votes[pos]=*votes[pos]+*JER_Cs[i];
			} /* if */ 		
		} /* for */ 

		for(i=0;i<solutions.Length();i++) {
			write_debug_report("%s -> %g\n",solutions[i]->getName()->get(),*votes[i]);
		} /* for */ 

		selected=0;
		for(i=0;i<solutions.Length();i++) {
			if (*votes[i]>*votes[selected]) {
				selected=i;
			} /* if */ 
		} /* for */ 

		solution_record=new FeatureTerm((char *)0,m_ontology->get_sort("problem-prediction"),1,
										"solution",new FeatureTerm(solutions[selected]));
	}

	return solution_record;
} /* AW_NOOSLearnerBrain::solve_problem_JEC */ 



FeatureTerm *AW_NOOSLearnerBrain::examine_JER(FeatureTerm *JER,Sort *sort)
{
	int Y=0,N=0;
	List<FeatureTerm> *cases;
	FeatureTerm *justification,*solution,*c,*cd,*cs;

	justification=JER->featureValueQuick("justification");
	solution=JER->featureValueQuick("solution");

	if (justification==0 || solution==0) {
		char *s;
		write_debug_report("examine_JER: ERROR 1\n");
		s=JER->toStringNOOS(m_memory);
		write_debug_report("%s\n",s);
		delete []s;
	} /* if */ 

	cases=m_casebase->SearchFT(sort);

	cases->Rewind();
	while(cases->Iterate(c)) {
		cd=get_description(c);
		if (justification->subsumes(cd)) {
			cs=get_solution(c);
			if (*cs==*solution) {
				Y++;
			} else {
				N++;
			} /* if */ 
			delete cs;
		} /* if */ 
		delete cd;
	} /* while */ 

	while(!cases->EmptyP()) cases->ExtractIni();
	delete cases;

	return new FeatureTerm((char *)0,m_ontology->get_sort("prediction-examination"),2,
						   "endorsing-cases",new FeatureTerm((Symbol *)0,Y,m_ontology),
						   "counter-examples",new FeatureTerm((Symbol *)0,N,m_ontology));
} /* AW_NOOSLearnerBrain::examine_JER */ 



float AW_NOOSLearnerBrain::local_confidence(FeatureTerm *JER,Sort *case_sort)
{
	FeatureTerm *XER;
	int Y,N;

	XER=examine_JER(JER,case_sort);				
	Y=XER->featureValueQuick("endorsing-cases")->getInt();
	N=XER->featureValueQuick("counter-examples")->getInt();
	delete XER;
	write_debug_report("<local_confidence: Y = %i, N = %i, C = %g>\n",Y,N,float(Y)/float(1+Y+N));
	return float(Y)/float(1+Y+N);
} /* AW_NOOSLearnerBrain::local_confidence */ 

